package tech.lq0.dreamaticvoyage.gui.menu;

import com.google.common.collect.Lists;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.ContainerData;
import net.minecraft.world.inventory.SimpleContainerData;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraftforge.event.entity.player.PlayerContainerEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.network.PacketDistributor;
import tech.lq0.dreamaticvoyage.block.entity.PhantasmalVoyagerBlockEntity;
import tech.lq0.dreamaticvoyage.gui.slot.*;
import tech.lq0.dreamaticvoyage.init.ItemRegistry;
import tech.lq0.dreamaticvoyage.init.MenuTypeRegistry;
import tech.lq0.dreamaticvoyage.item.misc.guardian.DreamGuardian;
import tech.lq0.dreamaticvoyage.network.DmvNetwork;
import tech.lq0.dreamaticvoyage.network.packet.ContainerComponentDataSyncPacket;

import java.util.ArrayList;
import java.util.List;

// TODO 完成menu的数据同步
@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.FORGE)
public class PhantasmalVoyagerMenu extends AbstractContainerMenu {

    private final Container container;
    private final ContainerData containerData;

    private final List<ContainerComponentDataSlot> containerComponentDataSlots = Lists.newArrayList();
    private final List<ServerPlayer> usingPlayers = new ArrayList<>();

    public static final int X_OFFSET = 100;
    public static final int Y_OFFSET = 41;

    public PhantasmalVoyagerMenu(int id, Inventory inventory) {
        this(id, inventory, new SimpleContainer(32), new SimpleContainerData(PhantasmalVoyagerBlockEntity.MAX_DATA_COUNT), new SimpleComponentData(PhantasmalVoyagerBlockEntity.MAX_VOYAGE_COUNT));
    }

    public PhantasmalVoyagerMenu(int id, Inventory inventory, Container container, ContainerData containerData, ContainerComponentData containerComponentData) {
        super(MenuTypeRegistry.PHANTASMAL_VOYAGER_MENU.get(), id);

        for (int i = 0; i < containerComponentData.getCount(); ++i) {
            this.containerComponentDataSlots.add(ContainerComponentDataSlot.forContainer(containerComponentData, i));
        }

        checkContainerSize(container, 32);
        checkContainerDataCount(containerData, PhantasmalVoyagerBlockEntity.MAX_DATA_COUNT);

        this.container = container;
        this.containerData = containerData;

        this.addSlot(new DreamGuardianSlot(container, 0, 170, 87, this.containerData.get(0) == 0));
        this.addSlot(new VoyagerFuelSlot(container, 1, 189, 87));
        this.addSlot(new VoyagerBookSlot(container, 2, 75, 183, this.containerData.get(0) == 0));
        this.addSlot(new VoyagerUpgradeSlot(container, 3, 285, 183, this.containerData.get(0) == 0));

        for (int i = 0; i < 7; ++i) {
            for (int j = 0; j < 4; ++j) {
                this.addSlot(new VoyageResultSlot(container, j + i * 4 + 4, 285 + j * 18, 53 + i * 18, this.containerData.get(0) == 0));
            }
        }

        this.addDataSlots(containerData);

        for (int i = 0; i < 3; ++i) {
            for (int j = 0; j < 9; ++j) {
                this.addSlot(new Slot(inventory, j + i * 9 + 9, 8 + j * 18 + X_OFFSET, 84 + i * 18 + Y_OFFSET));
            }
        }

        for (int k = 0; k < 9; ++k) {
            this.addSlot(new Slot(inventory, k, 8 + k * 18 + X_OFFSET, 142 + Y_OFFSET));
        }
    }

    @Override
    public void broadcastChanges() {
        List<ContainerComponentDataSyncPacket.Pair> pairs = new ArrayList<>();
        for (int i = 0; i < this.containerComponentDataSlots.size(); ++i) {
            ContainerComponentDataSlot dataSlot = this.containerComponentDataSlots.get(i);
            if (dataSlot.checkAndClearUpdateFlag())
                pairs.add(new ContainerComponentDataSyncPacket.Pair(i, dataSlot.get()));
        }

        if (!pairs.isEmpty()) {
            PacketDistributor.PacketTarget target = PacketDistributor.NMLIST.with(this.usingPlayers.stream().map(serverPlayer -> serverPlayer.connection.connection)::toList);
            DmvNetwork.CHANNEL.send(target, new ContainerComponentDataSyncPacket(this.containerId, pairs));
        }

        super.broadcastChanges();
    }

    // TODO 待添加升级槽位的快速填充
    @Override
    public ItemStack quickMoveStack(Player pPlayer, int pIndex) {
        ItemStack itemStack = ItemStack.EMPTY;
        Slot slot = this.slots.get(pIndex);
        if (slot.hasItem()) {
            ItemStack stack = slot.getItem();
            itemStack = stack.copy();
            if (pIndex >= 0 && pIndex <= 31) {
                if (!this.moveItemStackTo(stack, 32, 68, true)) {
                    return ItemStack.EMPTY;
                }
            } else {
                if (stack.getItem() instanceof DreamGuardian) {
                    if (!this.moveItemStackTo(stack, 0, 1, false)) {
                        return ItemStack.EMPTY;
                    }
                } else if (stack.is(Items.WRITABLE_BOOK)) {
                    if (!this.moveItemStackTo(stack, 2, 3, false)) {
                        return ItemStack.EMPTY;
                    }
                } else if (stack.is(ItemRegistry.PHANTASM_FUEL.get())) {
                    if (!this.moveItemStackTo(stack, 1, 2, false)) {
                        return ItemStack.EMPTY;
                    }
                } else if (pIndex >= 59 && pIndex < 68 && !this.moveItemStackTo(stack, 32, 59, false)) {
                    return ItemStack.EMPTY;
                } else {
                    if (!this.moveItemStackTo(stack, 59, 68, false)) {
                        return ItemStack.EMPTY;
                    }
                }
            }

            if (stack.isEmpty()) {
                slot.setByPlayer(ItemStack.EMPTY);
            } else {
                slot.setChanged();
            }

            if (stack.getCount() == itemStack.getCount()) {
                return ItemStack.EMPTY;
            }

            slot.onTake(pPlayer, stack);
        }

        return itemStack;
    }

    @Override
    public boolean stillValid(Player pPlayer) {
        return this.container.stillValid(pPlayer);
    }

    public ItemStack getDreamGuardian() {
        return this.container.getItem(0);
    }

    public void setVoyageState(int state) {
        this.containerData.set(0, state);
    }

    public int getVoyageState() {
        return this.containerData.get(0);
    }

    public int getVoyageProgress() {
        return this.containerData.get(1);
    }

    public int getVoyageMaxTime() {
        return this.containerData.get(2);
    }

    public List<Component> getComponents() {
        List<Component> components = new ArrayList<>();
        for (var slot : this.containerComponentDataSlots) {
            components.add(slot.get());
        }
        return components;
    }

    public void setData(int id, Component data) {
        this.containerComponentDataSlots.get(id).set(data);
    }

    @SubscribeEvent
    public static void onContainerOpened(PlayerContainerEvent.Open event) {
        if (event.getContainer() instanceof PhantasmalVoyagerMenu menu && event.getEntity() instanceof ServerPlayer serverPlayer) {
            menu.usingPlayers.add(serverPlayer);

            List<ContainerComponentDataSyncPacket.Pair> toSync = new ArrayList<>();
            for (int i = 0; i < menu.containerComponentDataSlots.size(); ++i) {
                toSync.add(new ContainerComponentDataSyncPacket.Pair(i, menu.containerComponentDataSlots.get(i).get()));
            }

            DmvNetwork.CHANNEL.send(PacketDistributor.PLAYER.with(() -> serverPlayer), new ContainerComponentDataSyncPacket(menu.containerId, toSync));
        }
    }

    @SubscribeEvent
    public static void onContainerClosed(PlayerContainerEvent.Close event) {
        if (event.getContainer() instanceof PhantasmalVoyagerMenu menu && event.getEntity() instanceof ServerPlayer serverPlayer) {
            menu.usingPlayers.remove(serverPlayer);
        }
    }
}
